home *** CD-ROM | disk | FTP | other *** search
- /*
- * K e r m i t File Transfer Utility
- *
- * UNIX Kermit, Columbia University, 1981, 1982, 1983
- * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz
- *
- * usage: kermit [csr][dlbe line baud escapechar] [f1 f2 ...]
- *
- * where c=connect, s=send [files], r=receive, d=debug,
- * l=tty line, b=baud rate, e=escape char (decimal ascii code).
- * For "host" mode Kermit, format is either "kermit r" to
- * receive files, or "kermit s f1 f2 ..." to send f1 .. fn.
- *
- *
- * Fixed up again for Unix, Jim Guyton 7/13/83 (Rand Corp)
- */
-
- #include <stdio.h> /* Standard UNIX definitions */
- #include <sgtty.h>
- #include <signal.h>
- #include <setjmp.h>
-
- /* Conditional Compilation: 0 means don't compile it, nonzero means do */
-
- #define UNIX 1 /* Conditional compilation for UNIX */
- #define TOPS_20 0 /* Conditional compilation for TOPS-20 */
- #define VAX_VMS 0 /* Ditto for VAX/VMS */
- #define IBM_UTS 0 /* Ditto for Amdahl UTS on IBM systems */
-
-
- /* Symbol Definitions */
-
- #define MAXPACK 94 /* Maximum packet size */
- #define SOH 1 /* Start of header */
- #define SP 32 /* ASCII space */
- #define CR 015 /* ASCII Carriage Return */
- #define DEL 127 /* Delete (rubout) */
- #define CTRLD 4
- #define BRKCHR CTRLD /* Default escape character for CONNECT */
-
- #define MAXTRY 5 /* Times to retry a packet */
- #define MYQUOTE '#' /* Quote character I will use */
- #define MYPAD 0 /* Number of padding characters I will need */
- #define MYPCHAR 0 /* Padding character I need */
- #define MYEOL '\n' /* End-Of-Line character I need */
- #define MYTIME 5 /* Seconds after which I should be timed out */
- #define MAXTIM 20 /* Maximum timeout interval */
- #define MINTIM 2 /* Minumum timeout interval */
-
- #define TRUE -1 /* Boolean constants */
- #define FALSE 0
-
-
- /* Global Variables */
-
- int size, /* Size of present data */
- n, /* Message number */
- rpsiz, /* Maximum receive packet size */
- spsiz, /* Maximum send packet size */
- pad, /* How much padding to send */
- timint, /* Timeout for foreign host on sends */
- numtry, /* Times this packet retried */
- oldtry, /* Times previous packet retried */
- fd, /* File pointer of file to read/write */
- remfd, /* File pointer of the host's tty */
- image, /* -1 means 8-bit mode */
- remspd, /* Speed of this tty */
- host, /* -1 means we're a host-mode kermit */
- debug; /* -1 means debugging */
-
- char state, /* Present state of the automaton */
- padchar, /* Padding character to send */
- eol, /* End-Of-Line character to send */
- escchr, /* Connect command escape character */
- quote, /* Quote character in incoming data */
- **filelist, /* List of files to be sent */
- *filnam, /* Current file name */
- recpkt[MAXPACK], /* Receive packet buffer */
- packet[MAXPACK]; /* Packet buffer */
-
- struct sgttyb
- rawmode, /* Host tty "raw" mode */
- cookedmode, /* Host tty "normal" mode */
- remttymode; /* Assigned tty line "raw" mode */
-
- jmp_buf env; /* Environment ptr for timeout longjump */
-
-
- /*
- * m a i n
- *
- * Main routine - parse command and options, set up the
- * tty lines, and dispatch to the appropriate routine.
- */
-
- main(argc,argv)
- int argc; /* Character pointer for */
- char **argv; /* command line arguments */
- {
- char *remtty,*cp; /* tty for CONNECT, char pointer */
- int speed, cflg, rflg, sflg; /* speed of assigned tty, */
- /* flags for CONNECT, RECEIVE, SEND */
- if (argc < 2) usage(); /* Make sure there's a command line. */
-
- cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */
-
- /* Initialize this side's SEND-INIT parameters */
-
- eol = CR; /* EOL for outgoing packets */
- quote = MYQUOTE; /* Standard control-quote char "#" */
- pad = 0; /* No padding */
- padchar = NULL; /* Use null if any padding wanted */
-
- speed = cflg = sflg = rflg = 0; /* Turn off all parse flags */
- remtty = 0; /* Default is host (remote) mode */
- image = FALSE; /* Default to 7-bit mode */
- escchr = BRKCHR; /* Default escape character */
-
- while ((*cp) != NULL) /* Get a character from the cmd line */
- switch (*cp++) /* Based on what the character is, */
- { /* do one of the folloing */
- case '-': break; /* Ignore dash (UNIX style) */
- case 'c': cflg++; break; /* C = CONNECT command */
- case 's': sflg++; break; /* S = SEND command */
- case 'r': rflg++; break; /* R = RECEIVE command */
- case 'e': if (argc--) /* E = specify escape char */
- escchr = atoi(*argv++); /* as ascii decimal number */
- else usage();
- if (debug) fprintf(stderr,"escape char is ascii %d\n",escchr);
- break;
- case 'l': if (argc--) /* L = specify tty line to use */
- remtty = *argv++;
- else usage();
- if (debug) fprintf(stderr,"line %s\n",remtty);
- break;
- #if UNIX /* This part only for UNIX systems */
- case 'b': if (argc--) speed = atoi(*argv++); /* Set baud rate */
- else usage();
- if (debug) fprintf(stderr,"speed %d\n",speed); break;
-
- case 'i': image = TRUE; break; /* Image (8-bit) mode */
- #endif /* UNIX */
-
- case 'd': debug = TRUE; break; /* Debug mode */
- }
-
- /* Done parsing */
-
- if ((cflg+sflg+rflg) != 1) usage(); /* Only one command allowed */
-
- remfd = 0; /* Start out as a host (remote) */
- host = TRUE;
-
- if (remtty) /* If another tty was specified, */
- {
- remfd = open(remtty,2); /* open it */
- if (remfd < 0) /* check for failure */
- {
- fprintf(stderr,"Kermit: cannot open %s\n",remtty);
- exit(-1); /* Failed, quit. */
- }
- host = FALSE; /* Opened OK, flag local (not host) */
- }
-
- /* Put the tty(s) into the correct modes */
-
- gtty(0,&cookedmode); /* Save current mode for later */
- gtty(0,&rawmode);
- rawmode.sg_flags |= (RAW|TANDEM);
- rawmode.sg_flags &= ~(ECHO|CRMOD);
-
- gtty(remfd,&remttymode); /* If local kermit, get mode of */
- /* assigned tty */
- remttymode.sg_flags |= (RAW|TANDEM);
- remttymode.sg_flags &= ~(ECHO|CRMOD);
-
- #if UNIX /* Speed changing for UNIX only */
- if (speed) /* User specified a speed? */
- {
- switch(speed) /* Get internal system code */
- {
- case 110: speed = B110; break;
- case 150: speed = B150; break;
- case 300: speed = B300; break;
- case 1200: speed = B1200; break;
- case 2400: speed = B2400; break;
- case 4800: speed = B4800; break;
- case 9600: speed = B9600; break;
- default: fprintf(stderr,"bad line speed\n");
- }
- remttymode.sg_ispeed = speed;
- remttymode.sg_ospeed = speed;
- }
- #endif /* UNIX */
-
- if (remfd) stty(remfd,&remttymode); /* Put asg'd tty in raw mode */
-
-
- /* All set up, now execute the command that was given. */
-
- if (cflg) connect(); /* CONNECT command */
-
- if (sflg) /* SEND command */
- {
- if (argc--) filnam = *argv++; /* Get file to send */
- else usage();
- filelist = argv;
- if (host) stty(0,&rawmode); /* Put tty in raw mode if remote */
- if (sendsw() == FALSE) /* Send the file(s) */
- printf("Send failed.\n"); /* Report failure */
- else /* or */
- printf("OK\n"); /* success */
- if (host) stty(0,&cookedmode); /* Restore tty */
- }
-
- if (rflg) /* RECEIVE command */
- {
- if (host) stty(0,&rawmode); /* Put tty in raw mode if remote */
- if (recsw() == FALSE) /* Receive the file */
- printf("Receive failed.\n"); /* Report failure */
- else /* or */
- printf("OK\n"); /* success */
- if (host) stty(0,&cookedmode); /* Restore tty */
- }
- }
-
- usage() /* Give message if user makes */
- { /* a mistake in the command */
- fprintf(stderr,
- "usage: kermit [csr][di][lbe] [line] [baud] [esc char] [f1 f2 ...]\n");
- exit();
- }
-
- /*
- * s e n d s w
- *
- * Sendsw is the state table switcher for sending
- * files. It loops until either it finishes, or
- * an error is encountered. The routines called by
- * sendsw are responsible for changing the state.
- *
- */
-
- sendsw()
- {
- char sinit(),sfile(),seof(),sdata(),sbreak();
-
- state = 'S'; /* Send initiate is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- while(TRUE) /* Do this as long as necessary */
- {
- switch(state)
- {
- case 'D': state = sdata(); break; /* Data-Send state */
- case 'F': state = sfile(); break; /* File-Send */
- case 'Z': state = seof(); break; /* End-of-File */
- case 'S': state = sinit(); break; /* Send-Init */
- case 'B': state = sbreak(); break; /* Break-Send */
- case 'C': return (TRUE); /* Complete */
- case 'A': return (FALSE); /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
-
- /*
- * s i n i t
- *
- * Send Initiate: Send my parameters, get other side's back.
- */
-
- char sinit()
- {
- int num, len; /* Packet number, length */
-
- if (debug) fprintf(stderr,"sinit\n");
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
- spar(packet); /* Fill up with init info */
- if (debug) fprintf(stderr,"n = %d\n",n);
-
- #if UNIX
- flushinput(); /* Flush pending input */
- #endif /* UNIX */
-
- spack('S',n,6,packet); /* Send an S packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': return(state); /* NAK */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, stay in S state */
- rpar(recpkt); /* Get other side's init info */
- if (eol == 0) eol = '\n'; /* Check and set defaults */
- if (quote == 0) quote = '#'; /* Control-prefix quote */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- if (debug) fprintf(stderr,"Opening %s\n",filnam);
- fd = open(filnam,0); /* Open the file to be sent */
- if (fd < 0) return('A'); /* if bad file descriptor, give up */
- if (!host) printf("Sending %s\n",filnam);
- return('F'); /* OK, switch state to F */
-
- case FALSE: return(state); /* Receive failure, stay in S state */
- default: return('A'); /* Anythig else, just "abort" */
- }
- }
-
-
- /*
- * s f i l e
- *
- * Send File Header.
- */
-
- char sfile()
- {
- int num, len; /* Packet number, length */
-
- if (debug) fprintf(stderr,"sfile\n");
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
- for (len=0; filnam[len] != '\0'; len++); /* Add up the length */
-
- spack('F',n,len,filnam); /* Send an F packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- if (n != (num=(--num<0)?63:num)) /* unless NAK for next packet, */
- return(state); /* which is just like an ACK */
- /* for this packet, fall thru to... */
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, stay in F state */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- size = bufill(packet); /* Get first data from file */
- return('D'); /* Switch state to D */
-
- case FALSE: return(state); /* Receive failure, stay in F state */
- default: return('A'); /* Something esle, just "abort" */
- }
- }
-
-
- /*
- * s d a t a
- *
- * Send File Data
- */
-
- char sdata()
- {
- int num, len; /* Packet number, length */
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
- spack('D',n,size,packet); /* Send a D packet */
-
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- if (n != (num=(--num<0)?63:num)) /* unless NAK for next packet, */
- return(state); /* which is just like an ACK */
- /* for this packet, fall thru to... */
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- if ((size = bufill(packet)) == EOF) /* Get data from file */
- return('Z'); /* If EOF set state to that */
- return('D'); /* Got data, stay in state D */
-
- case FALSE: return(state); /* Receive failure, stay in D */
- default: return('A'); /* Anything else, "abort" */
- }
- }
-
-
- /*
- * s e o f
- *
- * Send End-Of-File.
- */
-
- char seof()
- {
- int num, len; /* Packet number, length */
- if (debug) fprintf(stderr,"seof\n");
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
- spack('Z',n,0,packet); /* Send a 'Z' packet */
- if (debug) fprintf(stderr,"seof1 ");
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, fail */
- if (n != (num=(--num<0)?63:num)) /* ...unless for previous packet, */
- return(state); /* in which case, fall thru to ... */
- case 'Y': /* ACK */
- if (debug) fprintf(stderr,"seof2 ");
- if (n != num) return(state); /* If wrong ACK, hold out */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* and bump packet count */
- if (debug) fprintf(stderr,"closing %s, ",filnam);
- close(fd); /* Close the input file */
- if (debug) fprintf(stderr,"ok, getting next file\n");
- if (gnxtfl() == FALSE) /* No more files go? */
- return('B'); /* if not, break, EOT, all done */
- if (debug) fprintf(stderr,"new file is %s\n",filnam);
- return('F'); /* More files, switch state to F */
-
- case FALSE: return(state); /* Receive failure, stay in state Z */
- default: return('A'); /* Something else, "abort" */
- }
- }
-
-
- /*
- * s b r e a k
- *
- * Send Break (EOT)
- */
-
- char sbreak()
- {
- int num, len; /* Packet number, length */
- if (debug) fprintf(stderr,"sbreak\n");
- if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
-
- spack('B',n,0,packet); /* Send a B packet */
- switch (rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, fail */
- if (n != (num=(--num<0)?63:num)) /* ...unless for previous packet, */
- return(state); /* in which case, fall thru to ... */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, fail */
-
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* and bump packet count */
- return('C'); /* switch state to Complete */
-
- case FALSE: return(state); /* Receive failure, stay in state B */
- default: return ('A'); /* Other, "abort" */
- }
- }
-
-
- /*
- * r e c s w
- *
- * This is the state table switcher for receiving files.
- */
-
- recsw()
- {
- char rinit(),rdata(),rfile(); /* Use these procedures */
-
- state = 'R'; /* Receive is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
-
- while(TRUE) switch(state) /* Do until done */
- {
- case 'D': state = rdata(); break; /* Data receive state */
- case 'F': state = rfile(); break; /* File receive state */
- case 'R': state = rinit(); break; /* Send initiate state */
- case 'C': return(TRUE); /* Complete state */
- case 'A': return(FALSE); /* "Abort" state */
- }
- }
-
- /*
- * r i n i t
- *
- * Receive Initialization
- */
-
- char rinit()
- {
- int len, num; /* Packet length, number */
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
- switch(rpack(&len,&num,packet)) /* Get a packet */
- {
- case 'S': /* Send-Init */
- rpar(packet); /* Get the other side's init data */
- spar(packet); /* Fill up packet with my init info */
- spack('Y',n,6,packet); /* ACK with my parameters */
- oldtry = numtry; /* Save old try count */
- numtry = 0; /* Start a new counter */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('F'); /* Enter File-Send state */
-
- case FALSE: return (state); /* Didn't get a packet, keep waiting */
- default: return('A'); /* Some other packet type, "abort" */
- }
- }
-
-
- /*
- * r f i l e
- *
- * Receive File Header
- */
-
- char rfile()
- {
- int num, len; /* Packet number, length */
-
- if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
- switch(rpack(&len,&num,packet)) /* Get a packet */
- {
- case 'S': /* Send-Init, maybe our ACK lost */
- if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
- if (num == ((n==0)?63:n-1)) /* Previous packet, mod 64? */
- { /* Yes, ACK it again */
- spar(packet); /* with our Send-Init parameters */
- spack('Y',num,6,packet); /* ... */
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in this state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'Z': /* End-Of-File */
- if (oldtry++ > MAXTRY) return('A');
- if (num == ((n==0)?63:n-1)) /* Previous packet, mod 64? */
- { /* Yes, ACK it again. */
- spack('Y',num,0,0);
- numtry = 0;
- return(state); /* Stay in this state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'F': /* File Header, */
- if (num != n) return('A'); /* which is what we really want */
- /* The packet number must be right */
- if (!getfil(packet)) /* Try to open a new file */
- {
- fprintf(stderr,"Could not create %s\n"); /* Give up if can't */
- return('A');
- }
- else /* OK, give message */
- if (!host) printf("Receiving %s\n",packet);
- spack('Y',n,0,0); /* Acknowledge the file header */
- oldtry = numtry; /* Reset try counters */
- numtry = 0; /* ... */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Switch to Data state */
-
- case 'B': /* Break transmission (EOT) */
- if (num != n) return ('A'); /* Need right packet number here */
- spack('Y',n,0,0); /* Say OK */
- return('C'); /* Go to complete state */
-
- case FALSE: return(state); /* Couldn't get packet, keep trying */
- default: return ('A'); /* Some other packet, "abort" */
- }
- }
-
-
- /*
- * r d a t a
- *
- * Receive Data
- */
-
- char rdata()
- {
- int num, len; /* Packet number, length */
-
- if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
- switch(rpack(&len,&num,packet)) /* Get packet */
- {
- case 'D': /* Got Data packet */
- if (num != n) /* Right packet? */
- { /* No */
- if (oldtry++ > MAXTRY) return('A'); /* If too many tries, give up */
- if (num == ((n==0)?63:n-1)) /* Else check packet number */
- { /* Previous packet again? */
- spack('Y',num,6,packet); /* Yes, re-ACK it */
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in D, don't write out data! */
- }
- else return('A'); /* sorry wrong number */
- }
- /* Got data with right packet number */
- bufemp(packet,fd,len); /* Write the data to the file */
- spack('Y',n,0,0); /* Acknowledge the packet */
- oldtry = numtry; /* Reset the try counters */
- numtry = 0; /* ... */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Remain in data state */
-
- case 'F': /* Got a File Header */
- if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
- if (num == ((n==0)?63:n-1)) /* Else check packet number */
- { /* It was the previous one */
- spack('Y',num,0,0); /* ACK it again */
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in Data state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'Z': /* End-Of-File */
- if (num != n) return('A'); /* Must have right packet number */
- spack('Y',n,0,0); /* OK, ACK it. */
- close(fd); /* Close the file */
- n = (n+1)%64; /* Bump packet number */
- return('F'); /* Go back to Receive File state */
-
- case FALSE: return(state); /* No packet came, keep waiting */
- default: return('A'); /* Some other packet, "abort" */
- }
- }
-
- /*
- * c o n n e c t
- *
- * Establish a virtual terminal connection with the remote host, over an
- * assigned tty line.
- *
- */
-
- connect()
- {
- int parent; /* Fork handle */
- char c = NULL, r = '\r';
-
- if (host) /* If in host mode, nothing to connect to */
- {
- fprintf(stderr,"Kermit: nothing to connect to\n");
- return;
- }
-
- parent = fork(); /* Start fork to get typeout from remote host */
-
- if (parent) /* Parent passes typein to remote host */
- {
- printf("Kermit: connected.\r\n"); /* Give message */
- stty(0,&rawmode); /* Put tty in raw mode */
- read(0,&c,1); /* Get a character */
- while ((c&0177) != escchr) /* Check for escape character */
- { /* Not it */
- write(remfd,&c,1); /* Write the character on screen */
- c = NULL; /* Nullify it */
- read(0,&c,1); /* Get next character */
- } /* Until escape character typed */
- kill(parent,9); /* Done, get rid of fork */
- stty(0,&cookedmode); /* Restore tty mode */
- printf("\nKermit: disconnected.\n"); /* Give message */
- return; /* Done */
- }
- else /* Child does the reading from the remote host */
- {
- while(1) /* Do this forever */
- {
- read(remfd,&c,1);
- write(1,&c,1);
- }
- }
- }
-
- /*
- * KERMIT utilities.
- */
-
- clkint() /* Timer interrupt handler */
- {
- longjmp(env,TRUE); /* Tell rpack to give up */
- }
-
- /* tochar converts a control character to a printable one by adding a space */
-
- char tochar(ch)
- char ch;
- {
- return(ch + ' '); /* make sure not a control char */
- }
-
-
- /* unchar undoes tochar */
-
- char unchar(ch)
- char ch;
- {
- return(ch - ' '); /* restore char */
- }
-
-
- /*
- * ctl turns a control character into a printable character by toggling the
- * control bit (ie. ^A becomes A and A becomes ^A).
- */
-
- char ctl(ch)
- char ch;
- {
- return(ch ^ 64); /* toggle the control bit */
- }
-
-
- /*
- * s p a c k
- *
- * Send a Packet
- */
-
- spack(type,num,len,data)
- char type, *data;
- int num, len;
- {
- int i; /* Character loop counter */
- char chksum, buffer[100]; /* Checksum, packet buffer */
- register char *bufp; /* Buffer pointer */
-
- bufp = buffer; /* Set up buffer pointer */
- for (i=1; i<=pad; i++) write(remfd,&padchar,1); /* Issue any padding */
-
- *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */
- chksum = tochar(len+3); /* Initialize the checksum */
- *bufp++ = tochar(len+3); /* Send the character count */
- chksum = chksum + tochar(num); /* Init checksum */
- *bufp++ = tochar(num); /* Packet number */
- chksum = chksum + type; /* Accumulate checksum */
- *bufp++ = type; /* Packet type */
-
- for (i=0; i<len; i++) /* Loop for all data characters */
- {
- *bufp++ = data[i]; /* Get a character */
- chksum = chksum+data[i]; /* Accumulate checksum */
- }
- chksum = (chksum + (chksum & 192) / 64) & 63; /* Compute final checksum */
- *bufp++ = tochar(chksum); /* Put it in the packet */
- *bufp = eol; /* Extra-packet line terminator */
- write(remfd, buffer,bufp-buffer+1); /* Send the packet */
- if (debug) putc('.',stderr);
- }
-
- /*
- * r p a c k
- *
- * Read a Packet
- *
- */
-
- rpack(len,num,data)
- int *len, *num; /* Packet length, number */
- char *data; /* Packet data */
- {
- int i, done; /* Data character number, loop exit */
- char chksum, t, type; /* Checksum, current char, pkt type */
-
- #if UNIX /* TOPS-20 can't handle timeouts... */
- if (setjmp(env)) return FALSE; /* Timed out, fail */
- signal(SIGALRM,clkint); /* Setup the timeout */
- if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
- alarm(timint);
-
- flushinput(); /* Flush any pending input */
- #endif /* UNIX */
-
- while (t != SOH) /* Wait for packet header */
- {
- read(remfd,&t,1);
- if (!image) t &= 0177; /* Handle parity */
- }
-
- done = FALSE; /* Got SOH, init loop */
- while (!done) /* Loop to get a packet */
- {
- read(remfd,&t,1); /* Get character */
- if (!image) t &= 0177; /* Handle parity */
- if (t == SOH) continue; /* Resynchronize if SOH */
-
- chksum = t; /* Start the checksum */
- *len = unchar(t)-3; /* Character count */
-
- read(remfd,&t,1); /* Get character */
- if (!image) t &= 0177; /* Handle parity */
- if (t == SOH) continue; /* Resynchronize if SOH */
- chksum = chksum + t; /* Accumulate checksum */
- *num = unchar(t); /* Packet number */
-
- read(remfd,&t,1); /* Get character */
- if (!image) t &= 0177; /* Handle parity */
- if (t == SOH) continue; /* Resynchronize if SOH */
- chksum = chksum + t; /* Accumulate checksum */
- type = t; /* Packet type */
-
- for (i=0; i<*len; i++) /* The data itself, if any */
- { /* Loop for character count */
- read(remfd,&t,1); /* Get character */
- if (!image) t &= 0177; /* Handle parity */
- if (t == SOH) continue; /* Resynch if SOH */
- chksum = chksum + t; /* Accumulate checksum */
- data[i] = t; /* Put it in the data buffer */
- }
- data[*len] = 0; /* Mark the end of the data */
-
- read(remfd,&t,1); /* Get last character (checksum) */
- if (!image) t &= 0177; /* Handle parity */
- if (t == SOH) continue; /* Resynchronize if SOH */
- done = TRUE; /* Got checksum, done */
- }
- #if UNIX
- alarm(0); /* Disable the timer interrupt */
- #endif
-
- chksum = (chksum + (chksum & 192) / 64) & 63; /* Fold bits 7,8 into chksum */
- if (chksum != unchar(t)) return(FALSE); /* Check the checksum, fail if bad */
-
- return(type); /* All OK, return packet type */
- }
-
-
-
- /*
- * b u f i l l
- *
- * Get a bufferful of data from the file that's being sent.
- * Only control-quoting is done; 8-bit & repeat count prefixes are
- * not handled.
- */
-
- bufill(buffer)
- char buffer[]; /* Buffer */
- {
- int i; /* Loop index */
- char t,t7;
- i = 0; /* Init data buffer pointer */
- while(read(fd,&t,1) > 0) /* Get the next character */
- {
- if (image) /* In 8-bit mode? */
- {
- t7 = t & 0177; /* Yes, look at low-order 7 bits */
- if (t7 < SP || t7==DEL || t7==quote) /* Control character? */
- { /* Yes, */
- buffer[i++] = quote; /* quote this character */
- if (t7 != quote) t = ctl(t); /* and uncontrollify */
- }
- }
- else /* Else, ASCII text mode */
- {
- t &= 0177; /* Strip off the parity bit */
- if (t < SP || t == DEL || t == quote) /* Control character? */
- { /* Yes */
- if (t=='\n') /* If newline, squeeze CR in first */
- {
- buffer[i++] = quote;
- buffer[i++] = ctl('\r');
- }
- buffer[i++] = quote; /* Insert quote */
- if (t != quote) t=ctl(t); /* Uncontrollified the character */
- }
- }
- buffer[i++] = t; /* Deposit the character itself */
- if (i >= spsiz-8) return(i); /* Check length */
- }
- if (i==0) return(EOF); /* Wind up here only on EOF */
- return(i); /* Handle partial buffer */
- }
-
- /*
- * b u f e m p
- *
- * Get data from an incoming packet into a file.
- */
-
- bufemp(buffer,fd,len)
- char buffer[]; /* Buffer */
- int fd, len; /* File pointer, length */
- {
- int i; /* Counter */
- char t; /* Character holder */
-
- for (i=0; i<len; i++) /* Loop thru the data field */
- {
- t = buffer[i]; /* Get character */
- if (t == MYQUOTE) /* Control quote? */
- { /* Yes */
- t = buffer[++i]; /* Get the quoted character */
- if ((t & 0177) != MYQUOTE) /* Low order bits match quote char? */
- t = ctl(t); /* No, uncontrollify it */
- }
- if (image || (t != CR)) /* Don't pass CR in text mode */
- write(fd,&t,1); /* Put the char in the file */
- }
- }
-
-
- /*
- * g e t f i l
- *
- * Open a new file
- */
-
- getfil(filenm) /* Bizarre logic, as this is called */
- char *filenm; /* only with packet as the arg! */
- {
- if (filenm[0] == '\0')
- fd = creat(packet,0644); /* If filename known, use it */
- else
- fd = creat(filenm,0644); /* else use sourcefile name */
- return (fd > 0); /* Return false if file won't open */
- }
-
- /*
- * g n x t f l
- *
- * Get next file in a file group
- */
-
- gnxtfl()
- {
- if (debug) fprintf(stderr, "gnxtfl\n");
- filnam = *(filelist++);
- if (filnam == 0) return FALSE; /* If no more, fail */
- else return TRUE; /* else succeed */
- }
-
- /*
- * s p a r
- *
- * Fill the data array with my send-init parameters
- *
- */
-
- spar(data)
- char data[];
- {
- data[0] = tochar(MAXPACK); /* Biggest packet I can receive */
- data[1] = tochar(MYTIME); /* When I want to be timed out */
- data[2] = tochar(MYPAD); /* How much padding I need */
- data[3] = ctl(MYPCHAR); /* Padding character I want */
- data[4] = tochar(MYEOL); /* End-Of-Line character I want */
- data[5] = MYQUOTE; /* Control-Quote character I send */
- }
-
-
- /* r p a r
- *
- * Get the other host's send-init parameters
- *
- */
-
- rpar(data)
- char data[];
- {
- spsiz = unchar(data[0]); /* Maximum send packet size */
- timint = unchar(data[1]); /* When I should time out */
- pad = unchar(data[2]); /* Number of pads to send */
- padchar = ctl(data[3]); /* Padding character to send */
- eol = unchar(data[4]); /* EOL character I must send */
- quote = data[5]; /* Incoming data quote character */
- }
-
- #if UNIX
- flushinput()
- {
- long int count; /* Number of bytes ready to read */
- long int i; /* Number of bytes to read in loop */
-
- ioctl(remfd, FIONREAD, &count); /* See how many bytes pending read */
- if (!count) return; /* If zero, then no input to flush */
-
- while (count) { /* Loop till all are flushed */
- i = (count<sizeof(recpkt)) ? /* Read min of count and size of */
- count : sizeof(recpkt); /* the read buffer */
- read(remfd, recpkt, i); /* Read a bunch */
- count -= i; /* Subtract from amount to read */
- }
- }
- #endif /* UNIX */